#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Task.hpp"
using namespace std;

#define NUM 1024

class TcpClient
{
public: 
    TcpClient(const string &serverip, const uint16_t &serverport)
        :_sockfd(-1), _serverip(serverip), _serverport(serverport)
    {

    }
    void initClient()
    {
        // 1.创建client的套接字
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_sockfd == -1)
        {
            //客户端出错也可以有日志, 例如向microsoft报告错误日志信息, 但今天我们不这么搞了就, 直接cerr输出错误信息
            cerr << "create socket error!" << endl;
            exit(2);
        }
        // 2.tcp的客户端需不需要bind?[必须要!], 需不需要显示的bind呢?[不需要, 由OS来bind随机分配ip和port](自己显示bind的话, 这个端口号很有可能发生冲突)

    }
    void search()
    {
        string msg;
        cout << "Please Enter the filename searched : ";
        
        getline(cin, msg);
        
        cout << msg << endl;
        msg.insert(0, "S");
        write(_sockfd, msg.c_str(), msg.size());

        char buffer[NUM];
        int n = read(_sockfd, buffer, sizeof(buffer) - 1);
        if(n > 0)
        {
            // 目前把读到的数据当成字符串
            buffer[n] = 0;
            cout << "The following content returned by server are : \n" << buffer << endl;
        }
    }
    void transmit()
    {
        cout << "Please input the transmited file-name : ";
        //1.发送文件名到服务器
        string filename;
        getline(cin, filename);
        filename.insert(0, "T");
        filename += "\n";
        write(_sockfd, filename.c_str(), filename.size());

        cout << filename << endl;
        //2.发送文件内容到服务器
        string body;
        file_util::read(filename, body);
        cout << "发送文件内容"<< body<< endl;
        
        write(_sockfd, body.c_str(), body.size());

        char buffer[NUM];
        int n = read(_sockfd, buffer, sizeof(buffer) - 1);
        cout << "接收服务器返回的响应-> " << buffer<<endl;
        if(n > 0)
        {
            // 目前把读到的数据当成字符串
            buffer[n] = 0;
            cout << "The following content returned by server are : \n" << buffer << endl;
        }
    }
    void start()
    {
        // 3.客户端要发起连接请求
        //之前在UDP的时候,首次sendto的时候OS会自动给client绑定ip和port,而connect调用成功时,会自动bind成功
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        server.sin_family = AF_INET;
        server.sin_port = htons(_serverport);
        
        int n = connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
        if(n == -1) cerr << "socket connect error!" << endl;
        else
        {
            // string msg;
            while(true)
            {   
                int choice = 0;
                cout << "Please choose the function that you want achieve (transmit - 1 or search - 2) -> ";
                cin >> choice;
                getchar();
                if(choice == 1) transmit();
                else if(choice == 2) search();
                
            }
        }

    }
    ~TcpClient(){if(_sockfd >= 0) close(_sockfd);}//关闭客户端的_sockfd, 其实没必要关闭, 因为client退出的时候, 他的fd资源会被OS回收掉
private:
    int _sockfd;
    string _serverip;//客户端得知道server的网络信息, 然后向server发送数据
    uint16_t _serverport;
};



































